{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1. 以Lena为原始图像，通过OpenCV实现平均滤波，高斯滤波及中值滤波，比较滤波结果。 "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "import cv2 as cv\n",
    "\n",
    "img = cv.imread(\"./image/lena.jpg\")\n",
    "\n",
    "blur = cv.blur(img, (5, 5)) #平均滤波\n",
    "gaussBlur = cv.GaussianBlur(img, (5,5), 0)  #高斯滤波\n",
    "mediaBlur = cv.medianBlur(img, 3) #中值滤波\n",
    "\n",
    "cv.imshow(\"src\", img)\n",
    "cv.imshow(\"blur\", blur)\n",
    "cv.imshow(\"gaussBlur\", gaussBlur)\n",
    "cv.imshow(\"mediaBlur\", mediaBlur)\n",
    "\n",
    "cv.waitKey(0)\n",
    "cv.destroyAllWindows()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![三种滤波算法结果比较](http://px71ub40t.bkt.clouddn.com/%E6%BB%A4%E6%B3%A2.png)  \n",
    "平均滤波对高斯噪声表现较好，对椒盐噪声表现较差；中值滤波对椒盐噪声表现较好，对高斯噪声表现较差；高斯滤波较前两种而言，对图像进行滤波的同时你能够保留更多的灰度分布特征。\n",
    "\n",
    "\n",
    "### 2. 以Lena为原始图像，通过OpenCV使用Sobel及Canny算子检测，比较边缘检测结果。  \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import cv2 as cv\n",
    "\n",
    "img = cv.imread(\"./image/lena.jpg\")\n",
    "size = img.shape\n",
    "cv.imshow(\"src\", img)\n",
    "\n",
    "sobelX = cv.Sobel(img,cv.CV_16S,1,0)  #x方向Sobel检测\n",
    "sobelY = cv.Sobel(img,cv.CV_16S,0,1)  #y方向Sobel检测\n",
    "absX = cv.convertScaleAbs(sobelX)   # 转回uint8\n",
    "absY = cv.convertScaleAbs(sobelY)\n",
    "sobelImg = cv.addWeighted(absX,0.5,absY,0.5,0)  #xy方向合并\n",
    "cv.imshow(\"sobel\", sobelImg)\n",
    "\n",
    "gaussImg = cv.GaussianBlur(img, (3,3), 0)\n",
    "cannyImg = cv.Canny(gaussImg, 100, 150)\n",
    "cv.imshow(\"cannyImg\", cannyImg)\n",
    "\n",
    "cv.waitKey(0)\n",
    "cv.destroyAllWindows()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![三种滤波算法结果比较](http://px71ub40t.bkt.clouddn.com/%E8%BE%B9%E7%BC%98%E6%A3%80%E6%B5%8B.png)   \n",
    "通过比较运行结果我们可以看到Canny算子可以更好的检测出图像边缘。  \n",
    "\n",
    "### 3. 在OpenCV安装目录下找到课程对应演示图片(安装目录\\sources\\samples\\data)，首先计算灰度直方图，进一步使用大津算法进行分割，并比较分析分割结果。  \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import cv2 as cv\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "img1 = cv.imread(\"./image/Rice.png\",0)\n",
    "img2 = cv.imread(\"./image/pic2.png\",0)\n",
    "img3 = cv.imread(\"./image/pic6.png\",0)\n",
    "\n",
    "hist1 = cv.calcHist([img1], [0], None, [256], [0,255])\n",
    "plt.plot(hist1)\n",
    "plt.show()\n",
    "\n",
    "hist2 = cv.calcHist([img2], [0], None, [256], [0,255])\n",
    "plt.plot(hist2)\n",
    "plt.show()\n",
    "\n",
    "hist3 = cv.calcHist([img3], [0], None, [256], [0,255])\n",
    "plt.plot(hist3)\n",
    "plt.show()\n",
    "\n",
    "_,bw1=cv.threshold(img1,0,0xff,cv.THRESH_OTSU)\n",
    "_,bw2=cv.threshold(img2,0,0xff,cv.THRESH_OTSU)\n",
    "_,bw3=cv.threshold(img3,0,0xff,cv.THRESH_OTSU)\n",
    "\n",
    "cv.imshow(\"img1\", img1)\n",
    "cv.imshow(\"threshold1\", bw1)\n",
    "cv.imshow(\"img2\", img2)\n",
    "cv.imshow(\"threshold2\", bw2)\n",
    "cv.imshow(\"img3\", img3)\n",
    "cv.imshow(\"threshold3\", bw3)\n",
    "\n",
    "cv.waitKey(0)\n",
    "cv.destroyAllWindows()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![阈值分割](http://px71ub40t.bkt.clouddn.com/threshold1.png)   \n",
    "![阈值分割](http://px71ub40t.bkt.clouddn.com/threshold2.png)   \n",
    "![阈值分割](http://px71ub40t.bkt.clouddn.com/threshold3.png)   \n",
    "通过上图比较，大津算法对含噪声的图像和渐变图像检测边缘效果很差。   \n",
    "\n",
    "### 4. 使用米粒图像，分割得到各米粒，首先计算各区域(米粒)的面积、长度等信息，进一步计算面积、长度的均值及方差，分析落在3sigma范围内米粒的数量。     "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "length:11.31370748746044\n",
      "area:71.99999356269865\n",
      "length:20.14641587938584\n",
      "area:169.90244404862693\n",
      "length:24.90674841442579\n",
      "area:210.03833411290566\n",
      "length:6.0\n",
      "area:18.0\n",
      "length:19.677394790032814\n",
      "area:149.59974746713138\n",
      "length:25.942818571839766\n",
      "area:219.24444580082945\n",
      "length:9.0\n",
      "area:45.0\n",
      "length:15.0\n",
      "area:90.0\n",
      "length:21.078598992505846\n",
      "area:163.69209142858122\n",
      "length:27.872744534554037\n",
      "area:240.27525166852973\n",
      "length:21.402949557923943\n",
      "area:165.81050803745165\n",
      "length:27.0\n",
      "area:216.0\n",
      "length:24.57352824196111\n",
      "area:212.42445665036215\n",
      "length:27.727243773989645\n",
      "area:248.00005493164332\n",
      "length:26.899377183275494\n",
      "area:224.65916088331488\n",
      "length:43.97644832873776\n",
      "area:846.093213017215\n",
      "length:23.574759397579047\n",
      "area:189.61543053847547\n",
      "length:30.082641951196706\n",
      "area:687.103298318812\n",
      "length:22.02049804327113\n",
      "area:178.82924894009105\n",
      "length:26.682446311694914\n",
      "area:208.37644850791366\n",
      "length:27.68830339238514\n",
      "area:261.64634028280057\n",
      "length:27.174234568617482\n",
      "area:241.90237426757835\n",
      "length:26.38560554646736\n",
      "area:224.2000289917248\n",
      "length:20.870003614312534\n",
      "area:157.65555635052658\n",
      "length:25.811659090325353\n",
      "area:210.89675587625374\n",
      "length:20.19999923706056\n",
      "area:181.79991607666318\n",
      "length:29.40917620800196\n",
      "area:223.2002380372468\n",
      "length:30.18068638343893\n",
      "area:261.3012036178502\n",
      "length:25.957092329493268\n",
      "area:211.3302372923767\n",
      "length:18.000001525879103\n",
      "area:147.5999781799329\n",
      "length:26.16295090390226\n",
      "area:203.5\n",
      "length:28.24714654866966\n",
      "area:232.72147488198735\n",
      "length:30.0\n",
      "area:240.0\n",
      "length:28.600006103515625\n",
      "area:228.79996154789953\n",
      "length:26.244449714984764\n",
      "area:228.75264488021418\n",
      "length:37.073894936792435\n",
      "area:934.2829805147088\n",
      "length:15.652475842498529\n",
      "area:140.0\n",
      "length:22.0\n",
      "area:66.0\n",
      "length:27.333250098011092\n",
      "area:252.00011444091842\n",
      "length:29.05945443646888\n",
      "area:238.47952394800905\n",
      "length:30.57343396417197\n",
      "area:276.10589545595434\n",
      "length:30.401250455912887\n",
      "area:283.47168069519586\n",
      "length:28.301012769651148\n",
      "area:247.44723223524\n",
      "length:27.764134351718365\n",
      "area:210.8117942810126\n",
      "length:39.99929866801089\n",
      "area:884.49259555451\n",
      "length:57.235903791116684\n",
      "area:711.2924092952547\n",
      "length:27.89198487187102\n",
      "area:228.17861185041966\n",
      "length:28.436844831902487\n",
      "area:239.807699240245\n",
      "length:27.30396530592347\n",
      "area:240.82353677210278\n",
      "length:28.75612081774221\n",
      "area:279.41385229705594\n",
      "length:28.436852313139408\n",
      "area:223.0769962531448\n",
      "length:22.886155024628\n",
      "area:218.44673363192595\n",
      "length:28.0\n",
      "area:224.0\n",
      "length:30.410524493997904\n",
      "area:272.0000000000069\n",
      "length:25.17904733636963\n",
      "area:209.24614621675588\n",
      "length:21.964995165500923\n",
      "area:198.15386962890764\n",
      "length:29.557060756200215\n",
      "area:284.23965515141145\n",
      "length:23.255106965998813\n",
      "area:187.20023803718468\n",
      "length:27.070186685247226\n",
      "area:235.2785269317107\n",
      "length:30.2311522302217\n",
      "area:259.9227482723072\n",
      "length:30.405591591021544\n",
      "area:236.5\n",
      "length:29.911622862092752\n",
      "area:291.352757173686\n",
      "length:25.516209026361942\n",
      "area:184.0000000000101\n",
      "length:28.123286406133907\n",
      "area:246.47969088061575\n",
      "length:19.091872302446614\n",
      "area:161.9999084472915\n",
      "length:38.8013624238207\n",
      "area:510.76678645941473\n",
      "length:28.991380726046877\n",
      "area:225.50002098083593\n",
      "length:29.80723818495643\n",
      "area:278.4153050836423\n",
      "length:25.9384021868734\n",
      "area:232.00012207031253\n",
      "length:29.06826980906227\n",
      "area:262.5131455143188\n",
      "length:29.61345732927086\n",
      "area:285.42463974382997\n",
      "length:12.0\n",
      "area:84.0\n",
      "length:26.44580009013501\n",
      "area:254.31977691646162\n",
      "length:29.698484809834994\n",
      "area:273.0\n",
      "length:30.31696053114241\n",
      "area:272.05866555638966\n",
      "length:23.715410510589557\n",
      "area:215.95709975106638\n",
      "length:26.922662150124786\n",
      "area:240.37705792143456\n",
      "length:28.74443288769491\n",
      "area:250.17661693149597\n",
      "length:29.698484809834994\n",
      "area:273.0\n",
      "length:27.287635931767355\n",
      "area:250.46169292740584\n",
      "length:24.12228611824442\n",
      "area:227.07704544068736\n",
      "length:22.768406391091624\n",
      "area:172.79994506836033\n",
      "length:28.567060105600554\n",
      "area:261.4617802547807\n",
      "length:29.937869446935576\n",
      "area:271.2413742789315\n",
      "length:22.135943621178654\n",
      "area:168.00021362318267\n",
      "length:19.727880358043766\n",
      "area:155.67567196410695\n",
      "length:27.0\n",
      "area:189.0\n",
      "length:28.581434072930772\n",
      "area:259.3942647116452\n",
      "length:27.330413096552704\n",
      "area:251.82957272419375\n",
      "length:28.284271247461902\n",
      "area:220.0\n",
      "length:26.583397546151318\n",
      "area:239.88091859506417\n",
      "length:21.0\n",
      "area:168.0\n",
      "length:23.768999744807214\n",
      "area:207.44837964815179\n",
      "length:12.0\n",
      "area:24.0\n",
      "长度的均值:25.920950200612573\n",
      "面积的均值:244.19216980598878\n",
      "长度的方差:51.122179421682766\n",
      "面积的方差:23030.328185442977\n",
      "长度的标准差:7.149977581900713\n",
      "面积的标准差:151.7574650073036\n",
      "长度落在3sigma范围内的数量:93\n",
      "长度落在3sigma范围内的概率:0.9789473684210527\n",
      "面积落在3sigma范围内的数量:91\n",
      "面积落在3sigma范围内的概率:0.9578947368421052\n"
     ]
    }
   ],
   "source": [
    "import cv2 as cv\n",
    "import numpy as np\n",
    "import copy\n",
    "\n",
    "#统计数组中大于min，小于max的元素个数\n",
    "def countNum(arr, min, max):\n",
    "    count = 0\n",
    "    for v in arr:\n",
    "        if v >= min and v <= max:\n",
    "            count = count + 1\n",
    "    return count\n",
    "\n",
    "rice = cv.imread(\"./image/Rice.png\")\n",
    "gray = cv.cvtColor(rice, cv.COLOR_BGR2GRAY)\n",
    "\n",
    "#使用局部阈值的大津算法进行图像二值化\n",
    "bw = cv.adaptiveThreshold(gray,255, cv.ADAPTIVE_THRESH_MEAN_C, cv.THRESH_BINARY,101, 1)\n",
    "\n",
    "element = cv.getStructuringElement(cv.MORPH_CROSS, (3,3)) #形态学去噪\n",
    "bw = cv.morphologyEx(bw, cv.MORPH_OPEN, element) #开运算去噪\n",
    "\n",
    "seg = copy.deepcopy(bw)\n",
    "bin,cnts,hier = cv.findContours(seg, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)\n",
    "\n",
    "count = 0 #米粒总数\n",
    "areas = np.zeros(len(cnts)) #存储米粒的面积\n",
    "lens = np.zeros(len(cnts)) #存储米粒的长度\n",
    "for i in range(len(cnts), 0, -1):\n",
    "    c = cnts[i - 1]\n",
    "    area = cv.contourArea(c)\n",
    "    if(area < 10):\n",
    "        continue\n",
    "    count = count + 1\n",
    "    minAreaRect = cv.minAreaRect(c)\n",
    "    x,y,z,p = cv.boxPoints(minAreaRect)\n",
    "\n",
    "    #绘制包围矩形\n",
    "    cv.line(rice, (x[0], x[1]), (y[0], y[1]), (0, 0, 255), 1)\n",
    "    cv.line(rice, (y[0], y[1]), (z[0], z[1]), (0, 0, 255), 1)\n",
    "    cv.line(rice, (z[0], z[1]), (p[0], p[1]), (0, 0, 255), 1)\n",
    "    cv.line(rice, (p[0], p[1]), (x[0], x[1]), (0, 0, 255), 1)\n",
    "\n",
    "    #矩形的两条边\n",
    "    l1 = ((x[0] - y[0]) ** 2 + (x[1] - y[1]) ** 2) ** 0.5\n",
    "    l2 = ((x[0] - p[0]) ** 2 + (x[1] - p[1]) ** 2) ** 0.5\n",
    "    #计算长度\n",
    "    if l1 > l2:\n",
    "        line = l1\n",
    "    else:\n",
    "        line = l2\n",
    "    lens[i - 1] = line\n",
    "\n",
    "    #计算面积\n",
    "    minArea = l1*l2\n",
    "    areas[i-1] = minArea;\n",
    "    cv.putText(rice, str(round(minArea,2)), (x[0],x[1]), cv.FONT_HERSHEY_PLAIN, 0.5, (0,0xff, 0))\n",
    "    print(\"length:\" + str(line)) #打印米粒长度\n",
    "    print(\"area:\" + str(minArea)) #打印米粒面积\n",
    "\n",
    "\n",
    "len_mean = np.mean(lens) #长度的均值\n",
    "area_mean = np.mean(areas) #面积的均值\n",
    "len_var = np.var(lens) #长度的方差\n",
    "area_var = np.var(areas) #面积的方差\n",
    "len_std = np.std(lens) #长度的标准差\n",
    "area_std = np.std(areas) #面积的标准差\n",
    "\n",
    "print(\"长度的均值:\" + str(len_mean))\n",
    "print(\"面积的均值:\" + str(area_mean))\n",
    "print(\"长度的方差:\" + str(len_var))\n",
    "print(\"面积的方差:\" + str(area_var))\n",
    "print(\"长度的标准差:\" + str(len_std))\n",
    "print(\"面积的标准差:\" + str(area_std))\n",
    "\n",
    "lenNums = countNum(lens,len_mean - 3*len_std, len_mean + 3*len_std) #长度落在3sigma范围内的数量\n",
    "areaNums = countNum(areas,area_mean - 3*area_std, area_mean + 3*area_std) #面积落在3sigma范围内的数量\n",
    "\n",
    "print(\"长度落在3sigma范围内的数量:\" + str(lenNums))\n",
    "print(\"长度落在3sigma范围内的概率:\" + str(lenNums/len(cnts)))\n",
    "print(\"面积落在3sigma范围内的数量:\" + str(areaNums))\n",
    "print(\"面积落在3sigma范围内的概率:\" + str(areaNums/len(cnts)))\n",
    "\n",
    "cv.imshow(\"length\", rice)\n",
    "cv.imshow(\"OTSU2\", bw)\n",
    "\n",
    "cv.waitKey(0)\n",
    "cv.destroyAllWindows()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "运行结果：\n",
    "![阈值分割](http://px71ub40t.bkt.clouddn.com/rice.png)  \n",
    "长度的均值:25.920950200612573  \n",
    "面积的均值:244.19216980598878  \n",
    "长度的方差:51.122179421682766  \n",
    "面积的方差:23030.328185442977  \n",
    "长度的标准差:7.149977581900713  \n",
    "面积的标准差:151.7574650073036   \n",
    "长度落在3sigma范围内的数量:93  \n",
    "长度落在3sigma范围内的概率:0.9789473684210527  \n",
    "面积落在3sigma范围内的数量:91  \n",
    "面积落在3sigma范围内的概率:0.9578947368421052   \n",
    "\n",
    "### 5. 使用棋盘格及自选风景图像，分别使用SIFT、FAST及ORB算子检测角点，并比较分析检测结果。 "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import math\n",
    "import numpy as np\n",
    "import cv2 as cv\n",
    "\n",
    "img1 = cv.imread(\"./image/left06.jpg\")\n",
    "img2 = cv.imread(\"./image/home.jpg\")\n",
    "\n",
    "img_sift1 = img1.copy()\n",
    "img_fast1 = img1.copy()\n",
    "img_orb1 = img1.copy()\n",
    "\n",
    "img_sift2 = img2.copy()\n",
    "img_fast2 = img2.copy()\n",
    "img_orb2 = img2.copy()\n",
    "\n",
    "gray1 = cv.cvtColor(img1, cv.COLOR_BGR2GRAY)\n",
    "gray2 = cv.cvtColor(img2, cv.COLOR_BGR2GRAY)\n",
    "\n",
    "#sift角点检测\n",
    "sift = cv.xfeatures2d.SIFT_create()\n",
    "kpsift1 = sift.detect(gray1,None)\n",
    "siftResult1 = cv.drawKeypoints(gray1, kpsift1, img_sift1)\n",
    "cv.imshow('sift1', siftResult1)\n",
    "\n",
    "kpsift2 = sift.detect(gray2,None)\n",
    "siftResult2 = cv.drawKeypoints(gray2, kpsift2, img_sift2)\n",
    "cv.imshow('sift2', siftResult2)\n",
    "\n",
    "#fast角点检测\n",
    "fast = cv.FastFeatureDetector_create(threshold=70)\n",
    "kpfast1 =fast.detect(gray1, None)\n",
    "fastResult1 = cv.drawKeypoints(gray1, kpfast1, img_fast1, (255,0,0), cv.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)\n",
    "cv.imshow(\"fast1\", fastResult1)\n",
    "\n",
    "kpfast2 =fast.detect(gray2, None)\n",
    "fastResult2 = cv.drawKeypoints(gray2, kpfast2, img_fast2, (255,0,0), cv.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)\n",
    "cv.imshow(\"fast2\", fastResult2)\n",
    "\n",
    "#orb角点检测\n",
    "orb = cv.ORB_create()\n",
    "kporb1 = orb.detect(gray1, None)\n",
    "orbResult1 = cv.drawKeypoints(gray1, kporb1, img_orb1)\n",
    "cv.imshow(\"orb1\", orbResult1)\n",
    "\n",
    "kporb2 = orb.detect(gray2, None)\n",
    "orbResult2 = cv.drawKeypoints(gray2, kporb2, img_orb2)\n",
    "cv.imshow(\"orb2\", orbResult2)\n",
    "\n",
    "cv.waitKey(0)\n",
    "cv.destroyAllWindows()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![角点检测](http://px71ub40t.bkt.clouddn.com/%E8%A7%92%E7%82%B9%E6%A3%80%E6%B5%8B1.png)  \n",
    "![角点检测](http://px71ub40t.bkt.clouddn.com/%E8%A7%92%E7%82%B9%E6%A3%80%E6%B5%8B2.png)   \n",
    "通过比较可以看出sift在平坦处检测出了角点，fast大部分角点检测正确，orb有漏检"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
